<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Strict//EN">
<!--
//
// Copyright 2007-2008 Qianyan Cai
// Under the terms of the GNU Lesser General Public License version 2.1
//
-->
<html>
<head>
<meta name="Content-Type" content="text/html; charset=UTF-8" http-equiv="Content-Type">
<title>Objot 版本21 Java端手册</title>
<style>
	body	{ padding:0; margin:3ex; background:white; line-height:1.4; font-family:sans-serif; }
	h2		{ margin:3em 0 1em; padding:0 0 0.2ex; border-bottom:0.5ex solid #bcf; color:#730; }
	h3		{ margin:3em 0 1em; padding:0 0 0.1ex 1em; border-bottom:0.3ex solid #cdf; color:#730; }
	h4		{ margin:2em 0 1em 3ex; padding:0; color:#015; }
	h5		{ margin:2em 0 1em 3ex; padding:0; color:#032; }
	a:link		{ color: #04e; text-decoration:none; }
	a:visited	{ color: #60c; text-decoration:none; }
	a:hover		{ background:#ddf; }
	table	{ margin:0 3ex 1em; background:#f6f6f6; }
	td		{ padding:0 1ex 0.3ex; border-bottom:1px solid #dd8; }
	pre		{ margin:1ex 2ex; padding:0.6ex; border:1px solid #cc6; background:#f2f2f2; line-height:1.2; }
</style>
</head>
<body>


<!--@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@-->


<h1	align=center><a href=http://objot.info>Objot</a> 版本21 Java端手册</h1>
<hr>

<p>版权所有2007-2008蔡倩彦，采用GNU LGPL版本2.1许可模式。

<p>关于Javascript端开发请参考<a href=manual-js-zh.html>《Objot 版本21 Javascript端手册》</a>。
关于Actionscript端开发请参考<a href=manual-as-zh.html>《Objot 版本21 Actionscript端手册》</a>。

<ul>
	<li><a href=#demo>范例</a></li>
	<li><a href=#codec>数据编解码</a></li>
	<li><a href=#aspect>AOP</a></li>
	<li><a href=#container>IOC</a></li>
	<li><a href=#service>Service辅助</a></li>
	<li><a href=#util>辅助功能</a></li>
</ul>


<!--@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@-->


<h2 id=demo>范例</h2>

使用Servlet服务器部署范例。拷贝以下文件（或其他合适的版本）到WEB-INF/lib/目录中：
<ul>
	<li>antlr-2.7.6.jar</li>
	<li>asm.jar</li>
	<li>asm-attrs.jar</li>
	<li>cglib-2.1.3.jar</li>
	<li>commons-collections-2.1.1.jar</li>
	<li>commons-logging-1.0.4.jar</li>
	<li>dom4j-1.6.1.jar</li>
	<li>ejb3-persistence.jar</li>
	<li>hibernate-annotations.jar</li>
	<li>hibernate-commons-annotations.jar</li>
	<li>hibernate-validator.jar</li>
	<li>hibernate3.jar</li>
	<li>hsqldb.jar</li>
	<li>jta.jar</li>
</ul>
并且确保/tmp目录（或者C:\tmp之类）可写，或者修改hibernate.properties中hsqldb存储文件的设置。
对于Apache Tomcat，请使用6.0及以上版本，之前版本没有正确分离服务器根和web应用的commons-logging配置，这将导致无限递归。

访问demo/index.html。用Selenium访问demo/test/index.html可以进行测试。


<!--@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@-->


<h2 id=codec>数据编解码</h2>

<p>数据可以编码成字符串，以便传递给Javascript、Actionscript进行处理。可以从字符串中解码出数据。
可以被编解码的数据包括：
<table>
	<tr><th>Java<th>Javascript<th>Actionscript 3</tr>
	<tr><td>null<td>null undefined(只编码)<td>null undefined(只编码)</tr>
	<tr><td>boolean Boolean<td>boolean<td>Boolean</tr>
	<tr><td>int long(部分) float double Integer Long(部分) Float Double Number(作为long)<td>number<td>Number int</tr>
	<tr><td>String Clob<td>string<td>String</tr>
	<tr><td>Date Calendar(只编码)<td>Date<td>Date</tr>
	<tr><td>boolean[] int[] long[] &lt;T&gt;T[] Collection&lt;T&gt;<td>Array<td>Array</tr>
	<tr><td>其他Object Map&lt;String,Object&gt;<td>其他Object(非Function Boolean Number String)<td>其他Object(非Class Function)</tr>
</table>
其中，字符串是Unicode字符集，但不能包含一个特殊字符：'\x10'（即\u0010），Objot编解码时使用了这个特殊字符。

<p>Objot支持单继承类，Java端可以为类和属性指定别名。
列表、对象之间可以任意引用，构成的整个数据图都可以被编解码。

<p>可以定义规则，只处理局部（子图）。规则针对 被编解码的数据 和 规则key 设定。
规则、别名、对象创建等配置是代码性的，可以自行编写adapter等，支持annotation、file等配置形式，可以将业务代码与Objot完全分离。

<p>第一次编解码某个类的对象时，会生成bytecode来访问这个类，后续编解码这个类的对象时，不再有任何reflection，优化了效率。


<!--****************************************************************************************-->

<h3>public class objot.codec.<i>Codec</i></h3>

<p>编解码。默认的规则配置代码采用annotation配置方式。

<h5>public StringBuilder <i>enc</i>(Object o, Object rukeKey) throws Exception</h5>
编码，使用的规则与 每个编码的对象 及ruleKey相关。非线程安全。

<h5>public &lt;T&gt;T <i>dec</i>(char[] s, Class&lt;T&gt; cla, Object ruleKey) throws Exception<br>
public &lt;T&gt;T <i>dec</i>(char[] s, int sBegin, int sEnd1, Class&lt;T&gt; cla, Class ruleKey)</h5>
解码，使用的规则与 每个解码的对象 及ruleKey相关。返回数据图的根。
对根的解码将参照cla，如果不能符合cla，则抛出异常。
被解码的字符串范围是[sBegin,sEnd1)。非线程安全。

<h5>protected String <i>name</i>(Object o, Class c) throws Exception</h5>
编码时指定名字。<code>c == o.getClass()</code>，既可给每个类，也可以给每个对象指定不同的名字。
默认是：<pre>return o instanceof HashMap ? "" : c.getName();</pre>

<h5>protected Object <i>byName</i>(String name) throws Exception</h5>
解码时，根据名字得到对象，或者对象的类（生成的bytecode会调用无参数构造方法）。默认是：
<pre>return name.length() == 0 ? HashMap.class : Class.forName(name);</pre>

<h5>protected long <i>beLong</i>(long l) throws Exception</h5>
编码long时（包括日期时间的毫秒数）检查值，并返回这个值。
默认对超出-4503599627370496L至4503599627370496L（+-52bit）的值抛异常。
因为Javascript和Actionscript中数值只有52bit精度（IEEE754）。

<h5>protected boolean <i>arrayForList</i>;</h5>
Java端[]和Collection都编码为列表，解码时，如果根据上下文不能确定[]还是Collection，就由此field确定。
默认是<code>true</code>

<h5>protected Collection&lt;Object&gt; <i>newList</i>(Class c, int len) throws Exception</h5>
根据类和列表长度创建解码的Collection。默认是：
<pre>return c.isAssignableFrom(HashSet.class) ? new HashSet&lt;Object&gt;(len)
	: new ArrayList&lt;Object&gt;(len);</pre>

<h5>public Clazz <i>clazz</i>(Class c) throws Exception</h5>
分析一个类，返回分析结果，用于编解码的处理。既可能在编解码时被动调用，也可以主动调用。默认是：
<pre>// 调用getClazz()，若已经分析过，则直接返回分析结果
// 对c的每个field进行@Enc、@Dec等annotation分析
// 对c的每个method进行@Enc、@Dec等annotation分析
// 调用addClazz()，将分析的field,method情况传入，然后返回最终结果
// 默认使用PropertyAnno表示属性信息，请参考源代码
</pre>

<h5>protected final Clazz <i>getClazz</i>(Class c) throws Exception</h5>
返回类的分析结果，若尚未分析，则返回null。线程安全。

<h5>protected final Clazz <i>addClazz</i>(Class c, Property[] encs, Property[] decs, Map&lt;String, Property&gt; decNames) throws Exception<br>
protected final Clazz <i>addClazz</i>(Class c, Map&lt;?, Property&gt; encs, Map&lt;?, Property&gt; decs, Map&lt;String, Property&gt; decNames) throws Exception</h5>
对类做最后分析，添加并返回最终结果。
encs为需要编码的属性信息，decs为需要解码的属性信息。
decNames为解码属性名和信息的map，若为null则默认根据encs生成，不为null则重用这个map。
线程安全。参见Property类。


<h5>public <i>Codec</i>()</h5>
默认构造方法。类分析结果独立于其他Codec对象。

<h5>public <i>Codec</i>(Codec sameClazz)</h5>
构造方法。类分析结果和s指定Codec共用，并保持相同。

<!--****************************************************************************************-->

<h3>public @interface objot.codec.<i>Enc, Yes, No</i></h3>

<p>表示被标记的field、getter需要编码。
field、getter不能是private，getter可以是<code>getName()</code>也可以是<code>name()</code>这样的形式。

<p>可以设置参数，表示指定哪些key时需要编码，哪些禁止编码，作为编码规则。规则在后的优先。

<pre>@Enc(A.class) public String getName() { return name; }
@Enc({Yes.class, A.class}) public String name() { return name; }</pre>
表示：当key为A类或子类或对象时，需要编码；其他则禁止编码。

<pre>@Enc({A.class, B.class}) public String name;</pre>
表示：当key为B类或子类或对象时，需要编码；当key为A类或子类或对象时，需要编码；其他则禁止编码。

<pre>@Enc({No.class, C.class}) public String name;</pre>
表示：当key为C类或子类或对象时，禁止编码；其他则需要编码。

<pre>@Enc({No.class, C.class, Yes.class, A.class}) public String name;</pre>
表示：当key为A类或子类或对象时，需要编码；当key为C类或子类或对象时，禁止编码；其他则需要编码。

<pre>@Enc({D.class, Yes.class, A.class, B.class, No.class, C.class})
public String name;</pre>
表示：当key为C类或子类或对象时，禁止编码；当key为B类、A类或子类或对象时，需要编码；当key为D类或子类或对象时，禁止编码；其他则需要编码。

<p>当标记类时，其规则作用于类的各field、getter的@Enc、@EncDec的前端，对@Dec不起作用。

<pre>@Enc({A.class, No.class}) public class Foo {
	@Enc(C.class) public String name;
	public String name2;
}</pre>
对于name，当key为C类或子类或对象时，禁止编码；当key为A类或子类或对象时，需要编码；其他则禁止编码。
而name2，则不编码。

<!--****************************************************************************************-->

<h3>public @interface objot.codec.<i>Dec, EncDec</i></h3>

<p>@Dec与@Enc类似，表示被标记的field、setter允许解码。
field、setter不能是private，setter可以是<code>setName(String v)</code>也可以是<code>name(String v)</code>这样的形式。
@EncDec表示@Enc和@Dec的组合。

<p>当在类上标记@Dec时，其规则作用于各个field、setter的@Dec、@EncDec的前端，对@Enc不起作用。
当在类上标记@EncDec时，其规则作用于各个field、getter、setter的@Enc、@Dec、@EncDec的前端。

<p>标记了@EncDec，就不能再标记@Enc和@Dec，但@Enc和@Dec可以一起标记。

<!--****************************************************************************************-->

<h3>public @interface objot.codec.<i>NameEnc, NameDec, Name</i></h3>

<p>@NameEnc标记在field、getter上，表示编码时的名字，而不是field、getter名本身。
@NameDec标记在field、setter上，表示解码时的名字。
@Name表示@NameEnc和@NameDec的组合。

<p>标记了@Name，就不能再标记@NameEnc和@NameDec，但@NameEnc和@NameDec可以一起标记。

<!--****************************************************************************************-->

<h3>public class <i>Property</i></h3>

<p>关于属性编解码的信息。

<h5>protected Class <i>out</i>;</h5>
属性所在的declaring类。

<h5>protected Field <i>field</i>;</h5>
field属性，非field则为null。

<h5>protected Method <i>method</i>;</h5>
method属性，非method则为null。

<h5>protected String <i>name</i>;</h5>
属性名。
默认是<code>field.getName</code>或<code>Class2.propertyOrName(method, enc)</code>。

<h5>protected Class <i>cla</i>;</h5>
属性的类。
默认是<code>field.getType</code>、<code>method.getReturnType</code>或<code>method.getParameterTypes()[0]</code>。

<h5>protected Class <i>listElem</i>;</h5>
如果是Collection，表示元素的类。默认是
<pre>Class2.typeParamClass(
	field != null ? field.getGenericType()
	: enc ? method.getGenericReturnType()
		: method.getGenericParameterTypes()[0],
	0, Object.class);
</pre>

<h5>public <i>Property</i>(AccessibleObject fm, boolean enc)</h5>
默认构造方法，根据fm（必须为Field或Method）、enc设置各个默认值。

<h5>public void <i>into</i>(Map&lt;String, Property&gt; map)</h5>
将本属性信息放入一个map中，若已有同名的属性，抛出异常。

<h5>protected boolean <i>encodable</i>(Object o, Object ruleKey) throws Exception;</h5>
对应规则key，判断对象o的本属性是否允许编码。默认是true。

<h5>protected boolean <i>decodable</i>(Object o, Object ruleKey) throws Exception;</h5>
对应规则key，判断对象o的本属性是否允许解码。默认是true。

<!--****************************************************************************************-->

<h3>灵活的配置</h3>

<p>结合使用规则、别名，可以针对不同需求，给数据进行不同的编码。例如：
<pre>package demo; ...
public class User {
	@EncDec // 对于任何key，均可编解码
	public Integer id;

	protected String name;

	@Enc({DoUser.class, DoChat.class})
	public String name() {
		return name;
	}
	@Dec({DoSign.class, DoUser.class})
	public void name(String v) {
		name = v;
	}

	@Dec(DoUser.class)
	public List&lt;User&gt; friends;

	@Enc(DoUser.class) // key为DoUser类或子类或对象，需编码
	@Name("friends") // 编码名称为friends，因为不可解码，所以解码名称没有意思
	public List&lt;User&gt; friends_;
}
</pre>

<p>也可以编写访问配置文件的代码，从而支持文件式配置。例如：
<pre>// 读取配置文件
// 根据配置文件生成 相关类的创建模式，例如 使用IOC和AOP创建
Codec c = new Codec() {
	@Override
	protected Object byName(String name) throws Exception {
		// 根据已生成的创建模式和name创建对象
	}
	@Override
	protected Object clazz(Class c) throws Exception {
		Object z = getClazz(c); if (z != null) return z;
		Property[] encs, decs;
		// 根据c从配置文件中寻找相关配置
		// 如果无相关配置，则抛出异常，或者return super.clazz(c)
		// 找到配置，则根据编码配置，依次创建Prop类，生成encs数组
		// 找到配置，则根据解码配置，依次创建Prop类，生成decs数组
		return addClazz(c, false, encs, decs, null);
	}
};
class Prop extends Property {
	Prop(AccessibleObject fm, boolean enc) throws Exception {
		super(fm, enc);
		// 其他属性分析工作
	}
	@Override
	protected boolean encodable(Object o, Object ruleKey) throws Exception {
		// 根据key判断是否允许编码本属性
	}
	@Override
	protected boolean decodable(Object o, Object ruleKey) throws Exception {
		// 根据key判断是否允许解码本属性
	}
}
</pre>

<p>编解码前，先创建Codec对象：
<pre>Codec codec = new Codec();</pre>
或创建Codec子类对象，并可改变默认行为：
<pre>Codec codec = new Codec() {
	// 加上包名
	@Override
	protected Object byName(String name) throws Exception {
		return name.length() == 0 ? HashMap.class
			: Class.forName("demo.".concat(name));
	}
	// 去掉包名
	@Override
	protected String name(Object o, Class&lt;?&gt; c) throws Exception {
		return o instanceof HashMap ? "" : objot.util.Class2.selfName(c);
	}
	// override clazz, addClazz 等方法，即可采用不同的配置方式 
}
</pre>

<p>然后用这个codec对象来编解码：
<pre>User u1 = new User();
u1.id = 1;
u1.name = "user1";
u1.friends = new ArrayList&lt;User&gt;();
User u2 = new User();
u2.id = 2;
u2.name = "user2";
u2.friends = new ArrayList&lt;User&gt;();
...
u1.friends.add(u1);
u1.friends.add(u2);
u2.friends.add(...);
...
u1.friends_ = u1.friends; // 设置临时数据
CharSequence s = codec.enc(u1, DoUser.class); // 编码u1，规则key为DoUser类
u1.friends_ = null; // 清除临时数据
v1 = codec.dec(s.toString().toCharArray(), Object.class, DoUser.class);
	// 规则key为DoUser，解码为v1，限制v1的类必须是Object
</pre>
只有u1设置了friends_，因此编码u1时，只有u1的friends_以friends的名字编码。
解码时，只有v1具有friends属性，因为编码字符串中，只有u1有friends数据。



<!--@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@-->


<h2 id=aspect>AOP</h2>

<p>Objot利用bytecode合成子类，实现轻量、快速而强大的AOP。
合成后，执行以local变量为主，没有reflection，效率比许多interception方式要高。

<p>允许使用常规的编程模式进行aspect编写，比before、after、catch那样分离的方式更加灵活。
配置是代码性的，可以自行编写adapter等，支持annotation、file等配置形式，可以将业务代码与Objot完全分离。

<!--****************************************************************************************-->

<h3>public abstract class objot.aspect.<i>Aspect</i></h3>

<p>各个aspect的直接父类。各个aspect子类weave后，合成为target类的子类。
所有对aspect子类的引用（例如常量、类型、方法等）全部被替换成 对target子类的引用。
aspect子类中的所有field、method（除了aspect方法）都一一合成为target子类的field、method。

<h5>&lt;init&gt;()</h5>
aspect子类的构造方法weave后，依据target类的各个构造方法，合成为target子类的各个构造方法。

<h5>protected abstract void <i>aspect</i>() throws Throwable</h5>
aspect的具体实现。此具体aspect方法weave后，依据各个target方法，合成为各个override方法。
参数和返回类型 被替换成target方法的参数和返回类型。
this对象被替换成target对象。
aspect方法可以抛出任何异常，给调用者，即使target方法没有声明。
target方法的调试信息指向aspect方法，因此不影响源代码调试。

<!--****************************************************************************************-->

<h3>public static class objot.aspect.<i>Aspect.Target</i></h3>

<p>在Aspect.aspect中，与target方法相关的功能。
在aspect之外（未weave）直接调用都抛出AbstractMethodError异常。
weave后，被替换成常量或指令。

<h5>public static String <i>name</i>()</h5>
target方法的名字。

<h5>public static String <i>descript</i>()</h5>
target方法的描述符。

<h5>public static String <i>target</i>()</h5>
target方法的名字及描述符。

<h5>public static &lt;T&gt;T <i>thiz</i>()</h5>
target对象，== aspect方法的this。

<h5>public static &lt;T&gt;Class&lt;T&gt; <i>clazz</i>()</h5>
target类。

<h5>public static void <i>invoke</i>()</h5>
执行target方法，参数不变。可以多次执行。

<h5>public static &lt;T&gt;Class&lt;T&gt; <i>returnClass</i>()</h5>
target方法声明的返回类。

<h5>public static &lt;T&gt;T <i>getReturn</i>()</h5>
target方法的返回值，原始类型为其box值，void为null。
必须在invoke()之后执行，注意try finally等情况，否则加载target子类时抛出某个Error异常。

<h5>public static void <i>setReturn</i>(Object o)</h5>
指定返回值，原始类型为其box值，void必须为null。
如果在invoke()之前执行，则invoke()执行后的返回值优先。
如果invoke()不执行且非void，则必须指定一个返回值，否则加载target子类时抛出某个Error异常。

<h5>public static &lt;T&gt;T <i>data</i>()</h5>
获得为本override方法指定的数据。参见objot.aspect.Weaver.forWeave。

<!--****************************************************************************************-->

<h3>public abstract class objot.aspect.<i>Weaver</i></h3>

<p>合成target子类。合成后没有额外的reflection。

<h5>public <i>Weaver</i>(Class... aspectClasses) throws Exception</h5>
创建一个weaver，指定aspect。
指定多个aspect则合成多个target子类，在前的aspect在最外层，target在最内层。

<h5>public synchronized &lt;T&gt;Class&lt;T&gt; <i>weave</i>(Class&lt;T&gt; target) throws Exception</h5>
合成target子类。target类不能是Aspect或子类，不能是原始类、接口、abstract或final类。
必须有至少一个public或protected的构造方法。合成的每个target子类分别在每个aspect的package中。
返回的类是最外层的target子类。

<h5>protected abstract Object <i>forWeave</i>(Class&lt;? extends Aspect&gt; ac, Method m) throws Exception</h5>
针对每个aspect和每个target方法的组合，判断是否需要weave，并指定一个数据。
如果返回this（即Weaver对象本身），表示不要weave。
返回其他则weave，并作为override方法的相关数据，供<code>Target.data()</code>使用，每个aspect每个target方法的组合一个数据。

<!--****************************************************************************************-->

<h3>灵活的配置</h3>

<p>可以在forWeave方法中编写标记访问代码，从而支持标记式配置。例如：
<pre>Weaver w = new Weaver(SignAspect.class, TransactionAspect.class) {
	@Override
	protected Object forWeave(Class&lt;? extends Aspect&gt; ac, Method m)
			throws Exception {
		if (ac == SignAspect.class)
			return m.isAnnotationPresent(Sign.class) ? this : null;
		if (ac == TransactionAspect.class)
			return m.isAnnotationPresent(Transaction.class) ? this
				: new TransactionAspect.Config(m);
		return this;
	}
};
</pre>

<p>也可以编写访问配置文件的代码，从而支持文件式配置。例如：
<pre>// 读取配置文件
Weaver w = new Weaver(/* 配置中列举的全部aspect */) {
	@Override
	protected Object forWeave(Class&lt;? extends Aspect&gt; ac, Method m)
			throws Exception {
		// 根据m从配置文件中寻找相关配置
		// 如果无相关配置，则返回 this
		// 找到配置，则进一步判断需要weave的aspect，与ac比较
		// 相同，则创建数据，并返回数据
		// 无相同的，则返回this
	}
};
</pre>


<!--@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@-->


<h2>IOC</h2>

<p>Objot提供了轻量的基于bytecode的高效容器来实现IOC。
合成子类后，创建容器没有reflection，没有线程同步，注入过程中也没有hash计算，效率很高。

<p>支持多种注入模式，为对象作用域的控制提供了相当灵活的方式。
配置是代码性的，可以自行编写adapter等，支持annotation、file等配置形式，可以将业务代码与Objot完全分离。

<!--****************************************************************************************-->

<h3>public abstract class objot.container.<i>Container</i></h3>

<p>各个容器的父类，子类是由bytecode合成的容器。各个容器对象可以组成层次关系，相互为父子关系。

<h5>public final Container <i>parent</i>()</h5>
本容器的父容器。null表示没有父容器。线程安全。

<h5>public final Container <i>rootParent</i>()</h5>
本容器的根容器（即最上层的父容器）。如果没有父容器，则返回自身。线程安全。

<h5>public final Container <i>create</i>()</h5>
创建副本（与本容器配置相同的容器），共享父容器。线程安全。

<h5>public final Container <i>create</i>(Container parent_)</h5>
创建副本，指定父容器。线程安全。

<h5>public final Container <i>createBubble</i>()</h5>
创建本容器、父容器、递归到根容器的每个副本，他们构成独立的层次。
与<code>createBubble(null)</code>效果相同。线程安全。

<h5>public final Container <i>createBubble</i>(Container until)</h5>
创建本容器、父容器、递归 未 到容器until的每个副本，他们构成独立的层次，共享容器until为父容器。
如果until不在本容器层次中，则抛出异常。线程安全。

<h5>public final Container <i>createBubble</i>(Container until, Container to)</h5>
创建本容器、父容器、递归 未 到容器until的每个副本，他们构成独立的层次，容器to替代until为父容器。
如果until不在本容器层次中，则抛出异常。线程安全。

<h5>public boolean <i>bound</i>(Class c)</h5>
判断本容器是否绑定了某个类。线程安全。

<h5>public Container <i>contain</i>(Class c)</h5>
返回绑定了某个类的本容器、父容器直到根容器。如果均无绑定，返回null。线程安全。

<h5>public final &lt;T&gt;T <i>get</i>(Class&lt;T&gt; c)</h5>
获取某个类的对象。对于Container.class，返回本容器。
如果本容器没有绑定此类，则递归到父容器。只有一种情况非线程安全。

<h5>public final &lt;T&gt;T <i>getNew</i>(Class&lt;T&gt; c)</h5>
获取某个类的对象。对于Container.class，则创建副本，共享父容器。对于single模式，则创建新对象。
如果本容器没有绑定此类，则递归到父容器。线程安全。

<h5>public final &lt;T&gt;T <i>set</i>(Class&lt;T&gt; c, T o)</h5>
设置某个类的对象，只能用于set模式，其他则抛出异常。
返回设置的对象。如果本容器没有绑定此类，则递归到父容器。线程安全。

<p>get、create、set方法均可能抛出任何异常，特别是容器内部调用绑定类的方法时，由这些方法抛出。

<!--****************************************************************************************-->

<h3>public @interface objot.container.<i>Inject, Inject.New, Inject.Single, Inject.Set, Inject.Parent</i></h3>

<p>标记需要注入的地方。标记类的注入模式。
也可以使用完全分离的配置方式，消除业务代码对这些annotation的依赖。

<p>new模式的类，每次注入都创建新对象。single模式的类，每次注入都使用同一个对象。
set模式的类，每次注入都使用Container.set方法指定的对象，调用set方法前是null。
parent模式的类，每次注入都从父容器获取，或者从可能的缓存中获取。

<p>对于single和set模式，即使是相同的绑定，在每个容器和每个副本之间，对象都是相互独立的。
如果不同容器需要共享同一个single或set的对象，则用parent模式、或不绑定类，并且共享同一个父容器，由父容器提供这个对象。

<p>可以将类静态绑定到一个对象上，这个对象在相同绑定的容器和副本间共享。如果绑定对象，则各个模式无效。

<p>可以对field、方法parameter的注入独立配置，允许使用某个类绑定，或单独绑定到一个对象，但不能单独指定注入模式。

<!--****************************************************************************************-->

<h3>public class objot.container.<i>Factory</i></h3>

<p>容器工厂。通过bind()和forBind()完成配置，然后合成容器。

<h5>public <i>Factory</i>()</h5>
默认的注入模式为single。默认绑定Container类为容器自身，single模式。

<h5>public <i>Factory</i>(Class&lt;? extends Annotation&gt; defaultMode_)</h5>
指定默认注入模式。绑定的类，如果没有标记注入模式，则使用这个默认模式。
默认绑定Container类为容器自身，single模式。

<h5>public final synchronized boolean <i>bound</i>(Class cla)</h5>
判断是否绑定了一个类。

<h5>public final synchronized Factory <i>bind</i>(Class... cla)</h5>
绑定多个类。返回本工厂。

<h5>public final synchronized Factory <i>bind</i>(Class cla)</h5>
绑定一个类。不能绑定Container的子类，不能绑定非public类，允许绑定原始类型。返回本工厂。

<h5>protected Object <i>forBind</i>(Class c, Bind b) throws Exception</h5>
配置一个类绑定。传入的Bind已经根据标记，设置了模式。
可以绑定到另外一个类，可以指定注入模式，可以绑定到一个对象。
对于原始类型，因为没有构造方法，只能使用set、parent模式，或者绑定box对象。
返回值被忽略。默认是<code>return null;</code>

<h5>protected Constructor <i>forBind</i>(Class c, Constructor[] ts) throws Exception</h5>
配置构造方法。从类的所有构造方法中，选择一个返回。默认是：
<pre>for (Constructor t: ts)
	if (t.isAnnotationPresent(Inject.class))
		return t;
return c.getDeclaredConstructor(); // 无参数的构造方法
</pre>
选择的构造方法必须是public not static。

<h5>protected AccessibleObject[] <i>forBind</i>(Class c, AccessibleObject[] fms) throws Exception</h5>
返回一个数组，由Field、Method、null组成，表示要按顺序注入field、方法，null跳过。
传入的fms数组，是一个由全部field、然后全部方法组成的数组，包括继承下来的。默认是：
<pre>for (int i = 0; i &lt; fms.length; i++)
	if ( !fms[i].isAnnotationPresent(Inject.class))
		fms[i] = null;
return fms;
</pre>
选择的field、方法必须是public not static。

<h5>protected Object <i>forBind</i>(Class cc, AccessibleObject fp, Class c, Type generic, Bind b) throws Exception</h5>
为选择的构造方法、field、方法配置各个参数。
cc为绑定类。fp为field，或方法参数objot.util.Parameter。
c为field.getType()，或parameter.cla。
generic为field.getGenericType()，或parameter.generic。
传入的Bind默认绑定到c类上。可以绑定到其他类，或绑定到一个对象。
返回值被忽略。默认是<code>return null;</code>

<p>绑定到其他类时，如果此类尚未配置绑定，则将在forBind方法返回后，由工厂主动绑定。

<p>注意：new模式的类之间不能循环依赖（例如A、B类相互引用，又都是new模式），否则注入时会导致无限递归，栈溢出。
构造方法参数之间不能循环依赖（例如A类构造方法参数引用B类，B类构造方法参数引用A类），否则注入时会导致无限递归，栈溢出。
对于single模式的类，可能因为构造方法中循环依赖而重复创建，容器发现这种情况后会抛出异常。

<h5>public final Container <i>create</i>(Container parent)</h5>
合成容器子类，并创建容器对象。指定父容器。容器创建采用eager模式。

<h5>public final Container <i>create</i>(Container parent, boolean lazy_)</h5>
合成容器子类，并创建容器对象。指定父容器。指定容器创建的模式。
推荐eager模式：容器创建时，也创建每个single模式的对象，这样Container.get和注入就是线程安全的。
但对于从父容器获取的对象，线程安全取决于父容器。
lazy模式：容器创建时，不创建single模式的对象，他们在第一次获取时创建。这样对他们的访问非线程安全。
容器创建后，还可以继续绑定类，然后再合成、创建增加了配置的容器。

<!--****************************************************************************************-->

<h3>public class objot.container.<i>Bind</i></h3>

<p>关于绑定的具体配置。

<h5>public Class <i>cla</i></h5>
<h5>public Class <i>box</i></h5>
<h5>public Bind <i>cla</i>(Class c)</h5>
获取绑定的类，默认是自身，可以绑定到其他类。box是<code>Class2.boxTry(cla, true)</code>。
cla()返回对象自身。

<h5>public Class&lt;? extends Annotation&gt; <i>mode</i></h5>
<h5>public Bind <i>mode</i>(Class&lt;? extends Annotation&gt; m)</h5>
获取预判断的注入模式，可以改变注入模式。
如果绑定到其他类，或绑定到对象，或配置field、方法参数时，此模式将被忽略。

<h5>public Object <i>obj</i></h5>
<h5>public Bind <i>obj</i>(Object o)</h5>
可以绑定到对象。对象的类型必须符合注入的要求，可以是原始类型的box对象。

<!--****************************************************************************************-->

<h3>灵活的配置</h3>

<p>使用默认的绑定参数做配置，则不需要override方法：
<pre>Container a = new Factory().bind(A.class, B.class).create(null, true);
Container b = new Factory(Inject.Set.class).bind(A.class, B.class).create(null);
</pre>

<p>可以按需override几个Factory.forBind方法，自定义配置。
例如单元测试test.container里的代码，以及文件式配置：
<pre>
// 读取配置文件
Container a = new Factory() {
	{
		bind(/* 配置中列举的类 */);
	}
	@Override
	protected Object forBind(Class c, Bind b) throws Exception {
		// 根据c从配置文件中寻找相关类
		// 如无相关类，则返回null
		// 找到类，则根据配置设置b，返回null
	}
	@Override
	protected Constructor forBind(Class c, Constructor[] ts) throws Exception {
		// 根据c从配置文件中寻找相关类（已找到）
		// 根据配置返回类的构造方法
	}
	@Override
	protected AccessibleObject[] forBind(Class c, AccessibleObject[] fms)
		throws Exception {
		// 根据c从配置文件中寻找相关类（已找到）
		// 根据配置返回类的field、方法数组
	}
	@Override
	protected Object forBind(Class cc, AccessibleObject fp, Class c, Type generic,
		Bind b) throws Exception {
		// 根据cc、fp从配置文件中寻找相关field、方法（已找到）
		// 根据配置设置b，返回null
	}
}.create(/* 根据配置指定父容器 */, /* 根据配置指定eager、lazy */);
</pre>


<!--@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@-->


<h2 id=service>Service辅助</h2>

<p>Objot还提供一些辅助类，方便开发面向服务的应用。
可以将业务代码发布成service，由Codec提供单个至多个参数的解码、返回结果和异常的编码。
支持文件http上传和下载，以及进度查询。

<!--****************************************************************************************-->

<h3>public class objot.service.</i>ServiceInfo</i></h3>

<p>关于service的一些基本信息。参看源代码。

<!--****************************************************************************************-->

<h3>public class objot.service.</i>ServiceHandler</i></h3>

<p>独立于传输协议的serivce调用处理。参考源代码，和范例的代码。

<p>用Codec将调用的参数字符串解码成参数对象，用reflection调用service方法。
将serivce方法返回对象做编码，返回字符串。抛出的异常默认编码为objot.util.Err。
调用时可以指定上下文容器，用于获取外部数据，可以附加参数字符串之外的参数用于文件上传等功能。

<p>通常编写子类，增加与持久会话、单次请求相对应的Container层次，并使用AOP辅助service方法。
处理service方法返回的byte[]和InputStream等情况。

<!--****************************************************************************************-->

<h3>public class objot.service.<i>CodecServlet</i> implements Servlet</h3>

<p>servlet处理。参考源代码，和范例的代码。

<p>支持http post的serivce请求，并按照UTF-8提取字符串，调用ServiceHandler子类。
如果ServiceHandler返回的是CharSequence对象，则以UTF-8 test/plain输出。
否则当做byte[]或InputStream，直接输出。

<p>请求时，提供上下文容器，包含HttpServletRequest, HttpServletSession等供ServiceHandler处理。
对于http文件上传，生成Input.Upload对象，既用于参数字符串提取和解码，也传递给ServiceHandler供serivce读取。
对于返回byte[]和InputStream，ServiceHandler可以在上下文容器中设置字符串值，指定mime类型，默认是application/octet-stream。

<p>对于进度查询使用固定的url格式，并返回进度文本。


<!--@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@-->


<h2 id=util>辅助功能</h2>

<p>参见源代码。

<!--****************************************************************************************-->

<h3>public class objot.util.<i>Array2</i></h3>

<p>0长度的常用数组。按长度创建数组，并复用0长度数组。按长度和类型创建数组。转换null数组为0长度数组。

<p>在数组中查找。二分查找。可指定Comparator来查找。

<p>数组按需扩容。按需收缩。按范围复制数组。数组拼接。

<p>Collection转换为数组。添加数组到Collection。

<p>数组、Collection拼接成字符串。

<!--****************************************************************************************-->

<h3>public class objot.util.<i>Bytes</i></h3>

<p>对byte[]、范围的封装。扩容。

<p>多种创建方式。从InputStream中读取全部字节。

<p>复制。比较。

<p>按byte、short、char、int、unsigned int、long读写。

<!--****************************************************************************************-->

<h3>public class objot.util.<i>Ints, Longs, Objects</i></h3>

<p>与Bytes相似。

<!--****************************************************************************************-->

<h3>public class objot.util.<i>Class2</i></h3>

<p>取对象的系统hash。类型转换、判断、box、unbox。

<p>类名、包名、路径名、资源名。类描述符。bean属性名。

<p>获得generic类的generic参数。按名称、modifier、参数类型查找field、method。
判断方法override。请求accessible特权。

<p>读取类的字节码。在ClassLoader中根据名称、bytecode定义类。

<p>查找一个包里的所有类。

<p>Throwable，转换为Exception，转换为RuntimeException。

<p>annotation互斥判断。

<!--****************************************************************************************-->

<h3>public class objot.util.<i>Err, Errs, ErrThrow</i></h3>

<p>对异常的封装，供objot.service.ServiceHandler使用。

<!--****************************************************************************************-->

<h3>public class objot.util.<i>Input, Input.Line, Input.Upload</i></h3>

<p>从InputStream中读取全部字节。读InputStream写OutputStream。

<p>依据分割符，按行读取InputStream。读取字节计数。

<p>解析http上传格式。

<!--****************************************************************************************-->

<h3>public class objot.util.<i>InvalidValueException, InvalidLengthException, InvalidRangeException</i></h3>

<p>意义更明确的几个异常。

<!--****************************************************************************************-->

<h3>public class objot.util.<i>Math2</i></h3>

<p>三个值取最大、最小。限制数值在一个范围中。

<p>对数值做index、length、range等检查。

<p>判断数值大小和范围。

<p>限制正、负数。加、减法溢出处理。

<p>floor、ceiling模式的整除、取余、对齐。2的幂。

<p>数值转换成字符、字符串。

<!--****************************************************************************************-->

<h3>public class objot.util.<i>Mod2</i> extends Modifier</h3>

<p>给出更详细的modifier的定义。补充一些分类定义。

<p>分类。匹配判断。转换成字符串。

<!--****************************************************************************************-->

<h3>public class objot.util.<i>Parameter</i> extends AccessibleObject implements Member</h3>

<p>表示方法参数。

<!--****************************************************************************************-->

<h3>public class objot.util.<i>String2</i></h3>

<p>空串判断。转换null字符串。

<p>查找字符、子字符串。提取子串。

<p>UTF-8转换。


<!--@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@-->


</body>
</html>
